package student.productions;

import java.util.Collections;
import java.util.Random;

import student.State;

public class Relation extends MutableNode implements EvaluableNode {
	//invariant for children: contains either one Condition, or Term Rel Term in that order.

	/** Describes a Relation of type: Term Rel Term */
	public static final int T_REL_T = 1;
	/** Describes a Relation of type: { Condition } */
	public static final int COND    = 2;
	
	/** This Relation's type: T_REL_T or COND */
	private int type;

	/**
	 * Constructor: creates an instance of Relation of type T_REL_T.
	 * @param t1 first Term of this Relation.
	 * @param r Rel between the two Terms.
	 * @param t2 second Term of this Relation.
	 */
	public Relation(Term t1, Rel r, Term t2) {
		type= T_REL_T;
		if(t1 != null && t2 != null && r != null){
			children.add(t1);
			children.add(r);
			children.add(t2);
		}
		else
			throw new IllegalArgumentException("None of the children of a Relation can be null.");
	}
	
	/**
	 * Constructor: creates an instance of Relation of type COND.
	 * @param c this Relation's Condition.
	 */
	public Relation(Condition c) {
		type= COND;
		if( c != null)
			children.add(c);
		else
			throw new IllegalArgumentException("The Condition child of a Relation cannot be null.");
	}

	@Override
	public void prettyPrint(StringBuffer sb) {
		switch(type){
		case T_REL_T:
			for(Node n : children)
				n.prettyPrint(sb);
			break;
		case COND:
			sb.append("{ ");
			children.get(0).prettyPrint(sb);
			sb.append("} ");
			break;
		}
	}

	@Override
	public boolean eval(State s) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void mutate(Program genome) {
		StringBuffer sb = new StringBuffer();
		prettyPrint(sb);
		sb.append("was changed to ");
		if(type == COND){
			children.set(0, AbstractNode.chooseCondition(genome, children.get(0)));//only thing possible to do
		} else{
			Random rnd = new Random();
			int mutationType = rnd.nextInt(3);
			if(mutationType <= 1){
				int child = rnd.nextInt(2) * 2;//0 or 2 (the indices of the Terms)
				children.set(child, AbstractNode.generateTerm(genome, children.get(child)));
			} else
				Collections.reverse(children);
		}
		prettyPrint(sb);
		System.out.println(sb);
	}

	@Override
	public Node duplicate() {
		if (type == COND) {
			Condition child= (Condition)children.get(0).duplicate();
			return new Relation(child);
		} else { // Type is T_REL_T and children has 3 children of type Term, Rel, Term.
			Term t1child= (Term)children.get(0).duplicate();
			Rel rchild= (Rel)children.get(1).duplicate();
			Term t2child= (Term)children.get(2).duplicate();
			return new Relation(t1child, rchild, t2child);
		}
	}

}
